<?php
/**
 * GioCMS
 * 
 * LICENSE
 *
 * This source file is subject to the GNU GENERAL PUBLIC LICENSE Version 2 
 * that is bundled with this package in the file LICENSE.txt.
 * It is also available through the world-wide-web at this URL:
 * http://www.gnu.org/licenses/gpl-2.0.txt
 * If you did not receive a copy of the license and are unable to
 * obtain it through the world-wide-web, please send an email
 * to license@ninhgio.com so we can send you a copy immediately.
 * 
 * @copyright	Copyright (c) 2010-2011 GioCMS (http://cms.ninhgio.com)
 * @license		http://www.gnu.org/licenses/gpl-2.0.txt GNU GENERAL PUBLIC LICENSE Version 2
 * @author		NinhGio - ninhgio@gmail.com
 * @since		1.0
 * @version		$Id:$
 */

class Gio_Core_Route
{
	protected $_routes = array();
	/**
	 * @var Gio_Core_Route
	 */
	static $_instance = null;
	
	/**
	 * @return Gio_Core_Route
	 */
	public static function getInstance()
	{
		if (null == self::$_instance) {
			self::$_instance = new self();
		}
		return self::$_instance;
	} 
	
	public function __construct()
	{
		$routesFile = array();
		$modules = Gio_Core_Module::getAllModules();
		if (empty($modules)) {
			return;
		}
		foreach ($modules as $index => $module) {
			$routesDir = ROOT_DIR . DS . 'modules' . DS . $module . DS . 'configs' . DS . 'routes';
			if (!file_exists($routesDir)) {
				continue;
			}
			$routesIterator = new DirectoryIterator($routesDir);
			foreach ($routesIterator as $route) {
				if ($route->isDot()) {
					continue;
				}
				$routeName = $route->getFilename();
				if (('CVS' == $routeName) || ('.svn' == strtolower($routeName)) 
						|| ('index.html' == $routeName)
						|| ('.htaccess' == $routeName)) {
	                continue;
	            }
	            
	            $routesFile[] = $routesDir . DS . $routeName;
			}
		}
		if (!empty($routesFile)) {
			foreach ($routesFile as $index1 => $routeFile) {
				$routesIni = @parse_ini_file($routeFile, true);
				foreach ($routesIni as $index2 => $routeItem) {
					$route = array();
					$route['name'] = (string)$index2;
					$route['frontend'] = (isset($routeItem['frontend']) && (string)$routeItem['frontend'] == 'true')
											? true : false;
					$route['url'] = (string)$routeItem['url'];
					$route['type'] = (string)$routeItem['type'];
					$route['reverse'] = (isset($routeItem['reverse'])) 
											? (string)$routeItem['reverse'] : null;
					$route['reverse_no_rewrite'] = (isset($routeItem['reverse_no_rewrite'])) 
											? (string)$routeItem['reverse_no_rewrite'] : null;											
					$route['module'] = (string)$routeItem['module'];
					$route['controller'] = (string)$routeItem['controller'];
					$route['action'] = (string)$routeItem['action'];
					$route['params'] = (isset($routeItem['params'])) 
											? $routeItem['params'] : null;
					$route['langKey'] = (isset($routeItem['langKey'])) 
											? $routeItem['langKey'] : null;
					$route['csrf'] = (isset($routeItem['csrf']))			
											? (array)$routeItem['csrf'] : null;
					$route['localization']['enable'] = (isset($routeItem['localization']['enable']) && (string)$routeItem['localization']['enable'] == 'true')			
											? 'true' : 'false';			
					$route['localization']['identifier'] = (isset($routeItem['localization']['identifier']))
											? (array)$routeItem['localization']['identifier'] : null;
					$this->_routes[$route['name']] = $route;
				}
			}
		}
		return $this;
	}
	
	public function setRoutes($routes)
	{
		$this->_routes = array_merge($this->_routes, $routes);
	}
	
	public function setRoute($name, $route)
	{
		$this->_routes[$name] = $route;
		return $this;
	}
	
	public function getRoutes($frontend = false)
	{
		if (!$frontend) {
			return $this->_routes;	
		}
		$routes = array();
		if ($this->_routes) {
			foreach ($this->_routes as $index => $route) {
				if (isset($route['frontend']) && $route['frontend'] == true) {
					$routes[] = $route;
				}
			}
		}
		return $routes;
	}
	
	public function get($name, $value = array()) {
		$name = (string)$name;
		if (isset($this->_routes[$name])) {
			$configs = Gio_Core_Config_Xml::getConfig('web');
			$request = Gio_Core_Request::getInstance();
			$configs->url = $request->getBaseUrl();
			$localization = Gio_Core_Config_Xml::getConfig('localization');
			
			$rewrite = ($configs->rewrite == 'true') ? '' : '_no_rewrite';

			$csrfString = null;
			$url = null;
			if (isset($this->_routes[$name]['csrf']) 
				&& (string)$this->_routes[$name]['csrf']['enable'] = 'true' 
				&& strtolower($this->_routes[$name]['csrf']['retrive']) == 'get')
			{
				$csrf = new Gio_Core_Csrf($name);
				$csrfString = $csrf->getTokenName() . '=' . $csrf->getToken();
			}
			
			switch ($this->_routes[$name]['type']) {
				case 'static':
					$url = ltrim($this->_routes[$name]['url' . $rewrite], '/');
					break;
				case 'regex':
					$maps = (array)$this->_routes[$name]['params'];
					if (null == $maps) {
						return;
					} else {
						$data = array();
						foreach ($maps as $k => $v) {
							$temp = isset($value[$v]) ? $value[$v] : null;
							$data[] = str_replace(' ', '+', $temp);
						}
						$url = vsprintf($this->_routes[$name]['reverse' .  $rewrite], $data);
						$url = ltrim($url, '/');
					}
					break;
			}
			
			$router = $this->_routes[$name];
			if (isset($router['localization']['enable']) 
				&& 'true' == $router['localization']['enable']
				&& 'true' == (string)$localization->enable) 
			{
				$lang = isset($value['language'])
						? $value['language']
						: Gio_Core_Request::getInstance()->getParam('lang');
				if ($lang != $localization->languages->default) {	
					$configs->url = rtrim($configs->url, '/') . '/' . $lang;
				}
			}
			$url = rtrim($configs->url, '/') . '/'. $url;
			
			if ($csrfString && strpos($url, '?') !== false) {
				$csrfString = '&' . $csrfString;
			} elseif ($csrfString) {
				$csrfString = '?' . $csrfString;
			}
			$url = $url . $csrfString;
			$url = str_replace('###admin_url_prefix###', $configs->admin->url_prefix, $url);
		
			return rtrim($url, '/') ;
		}
	}
	
	public function getRoute($name)
	{
		return (isset($this->_routes[$name])) ? $this->_routes[$name] : null;
	}
	
	public static function getCurrentRoute($return = false)
	{
		$routes = self::getInstance()->getRoutes();
		$request = Gio_Core_Request::getInstance();
		$configs = Gio_Core_Config_Xml::getConfig();
				
		$baseUrl = $request->getBaseUrl();
		$webUrl = (Gio_Core_Application::_initInstallChecker()) ? $configs->web->url : $baseUrl;
		$temp = str_replace($baseUrl, '', $webUrl);
		$rewrite = '';
		
		$uri = $request->getRequestUri();
		if (null == $uri) {
			$currentUrl = '';
		} else {
			$serverName = $request->getServerName();
			$serverPort = $request->getServerPort();
			$serverPort = ($serverPort == 80) ? '' : ':' . $serverPort;
			$uri = 'http://' . $serverName . $serverPort . $uri;
			$currentUrl = str_replace($webUrl, '', $uri);
			$currentUrl = rtrim(ltrim($currentUrl, '/'), '/');
		}
		
		foreach ($routes as $index => $route) {
			if (isset($route['url' . $rewrite])) {
				if (strtolower($route['type']) == 'regex') {
					$pattern = '/'.str_replace('/', '\/', '^'.$route['url' . $rewrite]).'$/';
					$pattern = str_replace('?', '\?', $pattern);
					$pattern = str_replace('###admin_url_prefix###', $configs->web->admin->url_prefix, $pattern);
					
					if (preg_match($pattern, $currentUrl, $matches)) {
						/**
						 * Set params
						 */
						$params = isset($route['params']) ? (array)$route['params'] : null;
						if (!empty($params)) {
							foreach ($params as $key => $value) {
								$request->setParam($key, $matches[$value]);
							}							
						}
						return $route;
					} else {
						continue;
					}	
				} else {
					if (rtrim(str_replace('###admin_url_prefix###', $configs->web->admin->url_prefix, $route['url' . $rewrite]), '/') == $currentUrl) 
					{
						return $route;
						break;
					}
				}		
			} else {
				continue;
			}
		}
		if ($return) {
			return null;
		}
		
		Modules_Core_Services_Exception::error('ROUTE_NOT_FOUND');
	}
}